package com.camel.auth.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.dao.SaTokenDaoRedisJackson;
import cn.dev33.satoken.sso.SaSsoProcessor;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.camel.auth.config.IamAuthConfig;
import com.camel.auth.model.SysUser;
import com.camel.auth.service.ISysUserService;
import com.camel.core.config.IamApplicationconfig;
import com.camel.core.entity.Result;
import com.camel.core.utils.RsaUtil;
import com.camel.core.utils.ResultUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * @author camel
 */
@RestController
@RequestMapping("sso")
public class UserController {

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IamAuthConfig iamAuthConfig;

    @Autowired
    private RsaUtil rsaUtil;

    @Autowired
    private SaTokenDaoRedisJackson saTokenDaoRedisJackson;

    @GetMapping("/me")
    public Result me() {
        int loginIdAsInt = StpUtil.getLoginIdAsInt();
        SysUser user = userService.getById(loginIdAsInt);
        user.setPassword(null);
        return ResultUtil.success(user);
    }

    /**
     * 根据ticket进行登录
     * @param ticket
     * @return
     */
    @GetMapping("/sso/doLoginByTicket")
    public SaResult doLoginByTicket(String ticket) {
        Object loginId = SaSsoProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
        if (loginId != null) {
            StpUtil.login(loginId);
            return SaResult.data(StpUtil.getTokenValue());
        }
        return SaResult.error("无效ticket：" + ticket);
    }

    @PostMapping("doLogin")
    public SaResult doLogin(String name, String pwd) {
        // 此处仅作模拟示例，真实项目需要从数据库中查询数据进行比对
        SysUser userInfo = userService.getOne(new QueryWrapper<SysUser>().eq("login_name", name));
        if (ObjectUtils.isEmpty(userInfo)) {
            // 混淆数据，找不到用户和密码不匹配使用相同的返回内容
            return SaResult.error("登录失败：请检查用户名密码");
        }
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userInfo.getUserId());
        // 30分钟内错误次数达到上限后不允许登录
        if (userInfo.getLoginFailNum() > iamAuthConfig.getMaxFailNum()) {
            if (!ObjectUtils.isEmpty(userInfo.getLoginDate())) {
                if ((System.currentTimeMillis() - userInfo.getLoginDate().getTime()) < IamApplicationconfig.LOGIN_LOCK_TIME) {
                    return SaResult.error("登陆失败次数已经累计达到" + iamAuthConfig.getMaxFailNum() + "次以上,请30分钟后再次尝试");
                }
            } else {
                sysUser.setLoginDate(new Date());
                userService.updateById(sysUser);
                return SaResult.error("登陆失败次数已经累计达到" + iamAuthConfig.getMaxFailNum() + "次以上,请30分钟后再次尝试");
            }
        }
        try {
            if (!ObjectUtils.isEmpty(userInfo) && userInfo.getLoginName().equals(name) && rsaUtil.verify(userInfo.getPassword(), pwd)) {
                StpUtil.login(userInfo.getUserId());
                saTokenDaoRedisJackson.set("x-token:login:permission:" + StpUtil.getTokenValue(), StringUtils.join(StpUtil.getPermissionList(), ","), StpUtil.getTokenTimeout());
                saTokenDaoRedisJackson.set("x-token:login:role:" + StpUtil.getTokenValue(), StringUtils.join(StpUtil.getRoleList(), ","), StpUtil.getTokenTimeout());
                // 登录成功后回滚错误次数
                sysUser.setLoginFailNum(0);
                userService.updateById(sysUser);
                return SaResult.data(StpUtil.getTokenInfo());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        sysUser.setLoginFailNum(ObjectUtils.isEmpty(userInfo.getLoginFailNum()) ? 0 : userInfo.getLoginFailNum() + 1);
        userService.updateById(sysUser);
        return SaResult.error("登录失败：请检查用户名密码");
    }

    /**
     * 查询登录状态  ---- http://localhost:8081/acc/isLogin
     * @return
     */
    @RequestMapping("isLogin")
    public SaResult isLogin() {
        return SaResult.ok("是否登录：" + StpUtil.isLogin());
    }

    /**
     * 查询 Token 信息  ---- http://localhost:8081/acc/tokenInfo
     * @return
     */
    @RequestMapping("tokenInfo")
    public SaResult tokenInfo() {
        return SaResult.data(StpUtil.getTokenInfo());
    }

    /**
     * 测试注销  ---- http://localhost:10000/user/logout
     * @return
     */
    @SaIgnore
    @RequestMapping("logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }
}
